using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
using System.Security.Permissions;

namespace qPrintComponent
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
    public class DevMode
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        internal string dmDeviceName;
        internal short dmSpecVersion;
        internal short dmDriverVersion;
        internal short dmSize;
        internal short dmDriverExtra;
        internal int dmFields;
        internal short dmOrientation;
        internal short dmPaperSize;
        internal short dmPaperLength;
        internal short dmPaperWidth;
        internal short dmScale;
        internal short dmCopies;
        internal short dmDefaultSource;
        internal short dmPrintQuality;
        internal short dmColor;
        internal short dmDuplex;
        internal short dmYResolution;
        internal short dmTTOption;
        internal short dmCollate;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        internal string dmFormName;
        internal UInt16 dmLogPixels;
        internal UInt32 dmBitsPerPel;
        internal UInt32 dmPelsWidth;
        internal UInt32 dmPelsHeight;
        internal UInt32 dmNup;
        internal UInt32 dmDisplayFrequency;
        internal UInt32 dmICMMethod;
        internal UInt32 dmICMIntent;
        internal UInt32 dmMediaType;
        internal UInt32 dmDitherType;
        internal UInt32 dmReserved1;
        internal UInt32 dmReserved2;
        internal UInt32 dmPanningWidth;
        internal UInt32 dmPanningHeight;



       
        internal DevMode(IntPtr DevModeHandle)
        {
            Marshal.PtrToStructure(DevModeHandle,this);
        }
        
        public override string ToString()
        {
            return FormName;
        }

        [Description(@"Specifies the 'friendly' name of the printer or display; for example, 'PCL/HP LaserJet' in the case of PCL/HP LaserJet. This string is unique among device drivers. Note that this name may be truncated.")]
        public string DeviceName
        {
            get { if (dmDeviceName == null) return ""; return dmDeviceName; }
        }
        [Description(@"Specifies the version number of the initialization data specification on which the structure is based.")]
        public short SpecVersion
        {
            get 
            {
                return dmSpecVersion; 
            }
        }
        [Description(@"Specifies the driver version number assigned by the driver developer.")]
        public short DriverVersion
        {
            get { return dmDriverVersion; }
        }
        [Description(@"Selects the orientation of the paper. This member can be either ORIENT_PORTRAIT (1) or ORIENT_LANDSCAPE (2).")]
        public Page_Orientation Orientation
        {
            get 
            {
                if (dmOrientation == 0) return Page_Orientation.PORTRAIT;
                Page_Orientation p;
                try { p =  (Page_Orientation)dmOrientation;}
                catch { p = Page_Orientation.PORTRAIT; }
                return p;
            }
            set
            {
                if ((dmOrientation != 0) && (dmOrientation != (short)value) && ((PrintComponent.SafePrinterHandle.PrinterInfoQ.Fields & 0x1) == 0x1))
                {
                    dmOrientation = (short)value;
                    UpdateDevMode(0x1);
                }
            }
        }
        [Description(@"Specifies the name of the form to use; for example, 'Letter' or 'Legal'.")]
        [TypeConverter(typeof(qPrintComponent.qPaperSizeConverter))]
        public string FormName
        {
            get { return dmFormName; }
            set
            {
                if (FormName != value)
                {
                    int f = PrintComponent.SafePrinterHandle.PrinterInfoQ.sPaperNames.IndexOf(value);
                    if (f != -1)
                    {
                        System.Drawing.Point pt = PrintComponent.SafePrinterHandle.PrinterInfoQ.PaperSizes[f];
                        dmFormName = value;
                        dmPaperSize = (short)PrintComponent.SafePrinterHandle.PrinterInfoQ.Papers[f];
                        dmPaperLength = (short)(pt.Y);
                        dmPaperWidth = (short)(pt.X);
                        UpdateDevMode(2 | 4 | 8 | 0x10000);
                    }
                }
            }
        }
        [Description(@"Selects the size of the paper to print on.")]
        public short PaperSize
        {
            get
            { return dmPaperSize; }
        }

        [Description(@"The length of the paper specified by the dmPaperSize member, either for custom paper sizes or for devices such as dot-matrix printers that can print on a page of arbitrary length. These values, along with all other values in this structure that specify a physical length, are in tenths of a millimeter.")]
        public short PaperLength
        {
            get { return dmPaperLength; }
        }
        [Description(@"The width of the paper specified by the dmPaperSize member, either for custom paper sizes or for devices such as dot-matrix printers that can print on a page of arbitrary length. These values, along with all other values in this structure that specify a physical length, are in tenths of a millimeter.")]
        public short PaperWidth
        {
            get { return dmPaperWidth; }
        }
        [Description(@"Specifies the factor by which the printed output is to be scaled. The apparent page size is scaled from the physical page size by a factor of dmScale/100. For example, a letter-sized page with a dmScale value of 50 would contain as much data as a page of 17- by 22-inches because the output text and graphics would be half their original height and width.")]
        public short Scale
        {
            get { return dmScale; }
            set
            {
                if ((value < 1001) && (value > 0) && (value != dmScale)  && ((PrintComponent.SafePrinterHandle.PrinterInfoQ.Fields & 0x10) == 0x10))
                {
                    dmScale = value;
                    UpdateDevMode(0x10); 
                }
            }
        }
        [Description(@"Selects the number of copies printed if the device supports multiple-page copies.")]
        public short Copies
        {
            get { return dmCopies; }
            set
            {
                if ((value != dmCopies) && ((PrintComponent.SafePrinterHandle.PrinterInfoQ.Fields & 0x100) == 0x100) && (value > 0) && (value <=  PrintComponent.SafePrinterHandle.PrinterInfoQ.Copies))
                {
                    dmCopies = value;
                    UpdateDevMode(0x100);
                }
                else
                    System.Windows.Forms.MessageBox.Show("The value has to be between 1 and " + PrintComponent.SafePrinterHandle.PrinterInfoQ.Copies.ToString());
            }
        }
        
        [Description(@"Specifies the paper source.")]
        [TypeConverter(typeof (qDefaultSourceConverter))]
        public string DefaultSource
        {
            get
            {
                string s = string.Empty;
                try
                {
                    int i = PrintComponent.SafePrinterHandle.PrinterInfoQ.iBinNames.IndexOf(dmDefaultSource);
                    if (i != -1) 
                        s = PrintComponent.SafePrinterHandle.PrinterInfoQ.sBinNames[i];
                }
                catch { }
                return s;

            }
            [PrintingPermission(SecurityAction.Demand, Level = PrintingPermissionLevel.AllPrinting)]
            set
            {
                if (DefaultSource != value)
                {
                    int i = PrintComponent.SafePrinterHandle.PrinterInfoQ.sBinNames.IndexOf(value);
                    if (i != -1)
                    {
                        dmDefaultSource = (short) PrintComponent.SafePrinterHandle.PrinterInfoQ.iBinNames[i];
                        UpdateDevMode(0x200);
                    }
                }
            }
        }

        [Description(@"DPI")]
        [TypeConverter(typeof(qPrintQualityConverter))]
        public string PrintQuality
        {
            get { return dmPrintQuality.ToString() + " DPI"; }
            set 
            {
                value = value.Replace(" DPI", "");
                if (short.TryParse(value, out dmPrintQuality))
                {
                    dmYResolution = dmPrintQuality;
                    UpdateDevMode(0x400 | 0x2000);
                }
            }
        }
        [Description(@"Switches between color and monochrome on color printers.")]
        public Print_Color Color
        {
            get
            {
                if (dmColor == 0) return Print_Color.MONOCHROME;
                Print_Color c;
                try { c =  (Print_Color)dmColor; }
                catch  { c = Print_Color.MONOCHROME; }
                return c;
            }
            set
            {
                if ((dmColor != (short)value) && ((PrintComponent.SafePrinterHandle.PrinterInfoQ.Fields & 0x800) == 0x800) && PrintComponent.SafePrinterHandle.PrinterInfoQ.CanProcessColor)
                {
                    dmColor = (short)value;
                    UpdateDevMode(0x800);
                }
                else
                    System.Windows.Forms.MessageBox.Show("The printer does not support color");
            }
        }
        [Description(@"Selects duplex or double-sided printing for printers capable of duplex printing.")]
        public Page_Duplex Duplex
        {
            get
            {
                if (dmDuplex == 0) return Page_Duplex.SIMPLEX;
                Page_Duplex d;
                try { d = (Page_Duplex)dmDuplex; }
                catch { d= Page_Duplex.SIMPLEX; }
                return d;
            }
            set
            {
                if ((dmDuplex != (short)value) && ((PrintComponent.SafePrinterHandle.PrinterInfoQ.Fields & 0x1000) == 0x1000) && PrintComponent.SafePrinterHandle.PrinterInfoQ.CanDuplex)
                {
                    dmDuplex = (short)value;
                    UpdateDevMode(0x1000);
                }
                else
                    System.Windows.Forms.MessageBox.Show("The printer does not support duplexing");
            }
        }
        [Description(@"Specifies how TrueType fonts should be printed.")]
        public Print_TrueType TTOption
        {
            get
            {
                if (dmTTOption == 0) return Print_TrueType.BITMAP;
                Print_TrueType t;
                try { t = (Print_TrueType)dmTTOption; }
                catch { t = Print_TrueType.BITMAP; }
                return t;
            }
        }
        [Description(@"Specifies whether collation should be used when printing multiple copies.")]
        public Printer_Collate Collate
        {
            get
            {
                if (dmCollate == 0) return Printer_Collate.FALSE;
                Printer_Collate c;
                try { c = (Printer_Collate)dmCollate; }
                catch { c= Printer_Collate.FALSE; }
                return c;
            }
            set
            {
                if ((dmCollate != (short)value) && ((PrintComponent.SafePrinterHandle.PrinterInfoQ.Fields & 0x8000) == 0x8000) && PrintComponent.SafePrinterHandle.PrinterInfoQ.CanCollate)
                    {
                        dmCollate = (short)value;
                        UpdateDevMode(0x8000);
                    }
                    else
                        System.Windows.Forms.MessageBox.Show("The printer does not support collating");
            }
        }

        [Description(@"Specifies where the NUP is done.")]
        public UInt32 Nup
        {
            get { return dmNup; }
        }
        [Description(@"Specifies how ICM is handled. For a non-ICM application, this member determines if ICM is enabled or disabled. For ICM applications, the system examines this member to determine how to handle ICM support.")]
        public Printer_ICMMethod ICMMethod
        {
            get
            {
                if (dmICMMethod == 0) return Printer_ICMMethod.NONE;
                Printer_ICMMethod m;
                try { m= (Printer_ICMMethod)dmICMMethod; }
                catch { m= Printer_ICMMethod.USER; }
                return m;
            }
        }
        [Description(@"Specifies which color matching method, or intent, should be used by default. This member is primarily for non-ICM applications. ICM applications can establish intents by using the ICM functions.")]
        public Printer_ICMIntend ICMIntent
        {
            get
            {
                if (dmICMIntent==0)  return Printer_ICMIntend.USER;
                Printer_ICMIntend i;
                try { i = (Printer_ICMIntend)dmICMIntent; }
                catch { i =  Printer_ICMIntend.USER; }
                return i;
            }
        }
        [Description(@"Specifies the type of media being printed on. ")]
        public string MediaType
        {
            get 
            {
                string s = string.Empty;
                try
                {
                    int i = PrintComponent.SafePrinterHandle.PrinterInfoQ.MediaTypes.IndexOf((int)dmMediaType);
                    if (i != -1)
                        s = PrintComponent.SafePrinterHandle.PrinterInfoQ.MediaNames[i];
                }
                catch { }
                return s;
            }
        }
        [Description(@"Specifies how dithering is to be done.")]
        public Printer_Dither DitherType
        {
            get
            {
                if (dmDitherType == 0) return Printer_Dither.NONE;
                Printer_Dither d;
                try { d =  (Printer_Dither)dmDitherType; }
                catch { d = Printer_Dither.USER; }
                return d;
            }
        }


        private bool UpdateDevMode(int field)
        {
            if (!PrintComponent.SafePrinterHandle.canUpdate)
                System.Windows.Forms.MessageBox.Show("no sufficient rights to Update");
            if (PrintComponent.SafePrinterHandle.IsInvalid) return false;
            dmFields = field;
            IntPtr ptr1 = PrintComponent.SafePrinterHandle.PrinterInfo2.GetIntPtrField(7);
            Marshal.StructureToPtr(this, ptr1, true);
            return PrintComponent.SafePrinterHandle.PrinterInfo2.SetIntPtrField(7, ptr1);
        }
    }
}

    
    